#include <stdint.h>
#include <stdio.h>
#include <task.h>
#include <keyboard.h>

kbListener		kbList[255] = {0};
uint32_t 		listpos = 0;
    
static const uint8_t kbdus_lower[] =
{
    0,0,'1','2','3','4','5','6','7','8','9','0','-','+','\b','\t','q','w','e','r','t','y','u','i','o','p','[',']','\n',
    0,'a','s','d','f','g','h','j','k','l',';','\'','`',0,'\\','z','x','c','v','b','n','m',',','.','/',0,0,0,' ',0,
    [72] = K_UP, [75] = K_LEFT, [77] = K_RIGHT, [80] = K_DOWN,
};

static const uint8_t kbdus_upper[] =
{
    0,0,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t','Q','W','E','R','T','Y','U','I','O','P','[',']','\n',
    0,'A','S','D','F','G','H','J','K','L',':','"','~',0,'|','Z','X','C','V','B','N','M','<','>','?',0,0,0,' ',0,
    [72] = K_UP, [75] = K_LEFT, [77] = K_RIGHT, [80] = K_DOWN,
};

bool kbd_shift_state;

void keyboard_register_listener(kbListener nlist)
{
	kbList[listpos++] = nlist;
}

static inline uint8_t wait_for_key(void)
{
    while(!(in8(0x64) & 0x01)){GUTS();}     // wait for the key-pressed bit to be set
    return in8(0x60);                       // return the scan code
}

void keyboard_task(void)
{
    uint8_t key;
    bool handled;
    uint32_t pos;
    
    listpos = 0;
    kbd_shift_state = false;
        
    while(1)
    {
        while(1)
        {
            handled = true;
            key = wait_for_key();
                    
            switch(key)
            {
                case 58:                /* CAPS LOCK */
                    kbd_shift_state ^= true;
                    break;
                case 42:                /* SHIFT */
                case 54:
                    kbd_shift_state = true;
                    break;
                case (42 + (1 << 7)):
                case (54 + (1 << 7)):
                    kbd_shift_state = false;
                    break;
                    
                default:
                    handled = false;
                    break;
            }
            
            if(!(key & 0x80) && handled == false){break;}       // if it's a key release code, ignore it
        }

        for(pos = 0; pos < listpos; pos++)  // hand out the char to our listeners
        {
            kbList[pos]((uint8_t)(kbd_shift_state > 0 ? kbdus_upper[key] : kbdus_lower[key]));
        }
    }
    
    kill_task(active_task_id);              // we should never reach this point, but just in case, let's not crash the system. ;-) 
}

